﻿using MetaQuotes.MT5WebAPI;
using MetaQuotes.MT5WebAPI.Common;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace MT5DataCollect
{
    public class MT5Service
    {
        public MT5WebAPI mT5WebAPI;
        public int timeout = 10000;
        Form1.ShowMsgDelegate showMsg;
        public List<string> mt5Groups = new List<string>()
        {
            "demo\\demoforex",
            "preliminaryAff"
        };

        uint pageSize = 100;

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="_showMsgDelegate"></param>
        public void INI(Form1.ShowMsgDelegate _showMsgDelegate)
        {
            try
            {
                showMsg = _showMsgDelegate;
                mT5WebAPI = new MT5WebAPI();
            }
            catch (Exception)
            {
                throw;
            }
        }

        #region 连接/断开连接 

        /// <summary>
        /// 将 Web 客户连接至交易服务器。
        /// </summary>
        /// <param name="server"></param>
        /// <param name="port"></param>
        /// <param name="login"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public MTRetCode Connect(string server, int port, ulong login, string password)
        {
            try
            {
                MTRetCode code = mT5WebAPI.Connect(server, port, login, password, MT5WebAPI.EnPumpModes.PUMP_MODE_NONE, MT5WebAPI.EnCryptModes.CRYPT_MODE_AES, timeout);
                showMsg($"MT5-Web 客户连接至交易服务器({server}){code.ToString()}");
                return code;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 从交易服务器与 Web 客户断开连接。
        /// </summary>
        /// <returns></returns>
        public void Disconnect()
        {
            try
            {
                mT5WebAPI.Disconnect();
                showMsg($"MT5-交易服务器与 Web 客户断开连接");
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 检查 Web 客户连接至交易服务器的状态。
        /// </summary>
        /// <returns></returns>
        public bool IsConnected()
        {
            try
            {
                return mT5WebAPI.IsConnected;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 向服务器发送空数据包以维持连接。
        /// </summary>
        /// <returns></returns>
        public MTRetCode Ping()
        {
            try
            {
                return mT5WebAPI.Ping();
            }
            catch (Exception)
            {
                throw;
            }
        }

        #endregion

        #region 交易品种

        public void GetSymbol(string server)
        {
            int total = 0;
            MTRetCode code;
            List<MTConSymbol> mTConSymbols = new List<MTConSymbol>();
            mT5WebAPI.SymbolTotal(out total);
            showMsg($"MT5-获取服务器({server})-交易品种数{total}个");
            //total = 10;
            for (int i = 0; i < total; i++)
            {
                code = mT5WebAPI.SymbolNext(i, out MTConSymbol mTConSymbol);
                showMsg($"MT5-获取服务器({server})-交易品种{mTConSymbol.Symbol}({i}){code.ToString()}");
                if (code == MTRetCode.MT_RET_OK)
                {
                    //mTConSymbols.Add(mTConSymbol);
                    DBService.SaveSymbol(mTConSymbol);
                }
            }
        }

        #endregion

        #region  组

        public List<MTConGroup> GetGroup()
        {
            MTRetCode code;
            List<MTConGroup> mTConGroups = new List<MTConGroup>();

            MTConGroup mTConGroup = new MTConGroup();
            code = mT5WebAPI.GroupGet("demo\\demoforex", out mTConGroup);
            if (code == MTRetCode.MT_RET_OK)
            {
                mTConGroups.Add(mTConGroup);
            }
            code = mT5WebAPI.GroupGet("preliminaryAff", out mTConGroup);
            if (code == MTRetCode.MT_RET_OK)
            {
                mTConGroups.Add(mTConGroup);
            }
            return mTConGroups;
        }

        #endregion

        #region  用户

        /// <summary>
        /// 获取所有用户
        /// </summary>
        public void GetUsers(string server,string type)
        {
            try
            {
                MTRetCode code;
                foreach (string group in mt5Groups)
                {
                    List<int> logins = new List<int>();
                    code = mT5WebAPI.UserLogins(group, out logins);
                    if (code == MTRetCode.MT_RET_OK)
                    {
                      
                        showMsg($"MT5-获取服务器({server})-组({group})的客户数{logins.Count}个");
                        if (logins.Count > 0)
                        {
                            foreach (int login in logins)
                            {
                                GetUsersModel model = new GetUsersModel()
                                {
                                    server = server,
                                    group = group,
                                    login = login,
                                    type = type
                                };
                                GetUsersObj(model);
                                //ThreadPool.QueueUserWorkItem(GetUsersObj, model);
                            }
                        }
                    }
                    else
                    {
                        showMsg($"MT5-获取服务器({server})-组({group})的客户失败：{code.ToString()}");
                    }
                }
            }
            catch (Exception)
            {

                throw;
            }
        }

        public class GetUsersModel
        {
            public string server { get; set; }
            public string group { get; set; }
            public int login { get; set; }
            public string type { get; set; }
            
        }

        public void GetUsersObj(object obj)
        {
            MTRetCode code;
            MTUser mtUser = new MTUser();
            GetUsersModel model = (GetUsersModel)obj;
            if (model.type == "User")
            {
                code = mT5WebAPI.UserGet((ulong)model.login, out mtUser);
                if (code == MTRetCode.MT_RET_OK)
                {
                    int count = DBService.SaveUser(mtUser, model.server, model.group);
                    showMsg($"MT5-获取服务器({model.server})-组({model.group})-交易账号({model.login})的客户信息{(count > 0 ? "成功" : "失败")}");
                }
                GetAccount(model);
            }
            else if (model.type == "Trade")
            {
                GetDeal(model);
            }
            else if (model.type == "TodayTrade")
            {
                GetPosition(model);
                GetOrder(model);
                GetHistory(model);
            }
            else if (model.type == "All")
            {
                code = mT5WebAPI.UserGet((ulong)model.login, out mtUser);
                if (code == MTRetCode.MT_RET_OK)
                {
                    int count = DBService.SaveUser(mtUser, model.server, model.group);
                    showMsg($"MT5-获取服务器({model.server})-组({model.group})-交易账号({model.login})的客户信息{(count > 0 ? "成功" : "失败")}");
                }
                GetAccount(model);
                GetPosition(model);
                GetDeal(model);
                GetOrder(model);
            }
        }

        #endregion

        #region 账号

        public void GetAccount(GetUsersModel model)
        {
            try
            {
                MTRetCode code;
                MTAccount mTAccount = new MTAccount();
                code = mT5WebAPI.UserAccountGet((ulong)model.login, out mTAccount);
                if (code == MTRetCode.MT_RET_OK)
                {
                    int count = DBService.SaveAccount(mTAccount);
                }
                else
                {
                    showMsg($"MT5-获取服务器({model.server})-组({model.group})的账号{model.login}：{code.ToString()}");
                }
            }
            catch (Exception)
            {

                throw;
            }
        }
        #endregion

        #region  订单

        /// <summary>
        /// 获取所有用户
        /// </summary>
        public void GetOrder(GetUsersModel model)
        {
            try
            {
                uint total = 0;
                MTRetCode code;
                List<ulong> orders = new List<ulong>();
                //long from = GettimeStamp(new DateTime(2023, 1, 1));
                //long to = GettimeStamp(DateTime.Now);
                code = mT5WebAPI.OrderGetTotal((ulong)model.login, out total);
                if (code == MTRetCode.MT_RET_OK)
                {
                    //计算页数
                    int pageNum = (int)Math.Ceiling(((decimal)total / (decimal)pageSize));
                    //变量所有页
                    for (int i = 0; i < pageNum; i++)
                    {
                        List<MTOrder> mTOrders = new List<MTOrder>();
                        uint offset = (uint)(i * pageSize);
                        code = mT5WebAPI.OrderGetPage((ulong)model.login, offset, pageSize, out mTOrders);
                        if (code == MTRetCode.MT_RET_OK)
                        {
                            showMsg($"MT5-获取服务器({model.server})-组({model.group})的客户{model.login}的全部订单{mTOrders.Count}条");
                            if (mTOrders.Count > 0)
                            {
                                orders.AddRange(mTOrders.Select(k => k.Order));
                                foreach (MTOrder mTOrder in mTOrders)
                                {
                                    int count = DBService.SaveOrder(mTOrder);
                                    showMsg($"MT5-获取服务器({model.server})-组({model.group})-交易账号({model.login})的全部订单信息({mTOrder.Order}){(count > 0 ? "成功" : "失败")}");
                                }
                            }
                        }
                        else
                        {
                            showMsg($"MT5-获取服务器({model.server})-组({model.group})的客户{model.login}的全部订单失败：{code.ToString()}");
                        }
                    }
                    int clearCount = DBService.ClearOrder(orders, model.login);
                    if (clearCount > 0)
                    {
                        showMsg($"MT5-清除服务器({model.server})-组({model.group})的客户{model.login}的订单{orders.Count}条");
                    }
                }
                else
                {
                    showMsg($"MT5-获取服务器({model.server})-组({model.group})的客户{model.login}的订单数失败：{code.ToString()}");
                }
            }
            catch (Exception)
            {

                throw;
            }
        }

        /// <summary>
        /// 获取所有用户
        /// </summary>
        public void GetHistory(GetUsersModel model)
        {
            try
            {
                uint total = 0;
                MTRetCode code;
                List<ulong> orders = new List<ulong>();
                long from = GettimeStamp(DateTime.Today.AddDays(-1));
                long to = GettimeStamp(DateTime.Today);
                code = mT5WebAPI.HistoryGetTotal((ulong)model.login, from,to, out total);
                if (code == MTRetCode.MT_RET_OK)
                {
                    //计算页数
                    int pageNum = (int)Math.Ceiling(((decimal)total / (decimal)pageSize));
                    //变量所有页
                    for (int i = 0; i < pageNum; i++)
                    {
                        List<MTOrder> mTOrders = new List<MTOrder>();
                        uint offset = (uint)(i * pageSize);
                        code = mT5WebAPI.HistoryGetPage((ulong)model.login, from, to, offset, pageSize, out mTOrders);
                        if (code == MTRetCode.MT_RET_OK)
                        {
                            showMsg($"MT5-获取服务器({model.server})-组({model.group})的客户{model.login}的订单{mTOrders.Count}条");
                            if (mTOrders.Count > 0)
                            {
                                orders.AddRange(mTOrders.Select(k => k.Order));
                                foreach (MTOrder mTOrder in mTOrders)
                                {
                                    int count = DBService.SaveOrder(mTOrder);
                                    showMsg($"MT5-获取服务器({model.server})-组({model.group})-交易账号({model.login})的订单信息({mTOrder.Order}){(count > 0 ? "成功" : "失败")}");
                                }
                            }
                        }
                        else
                        {
                            showMsg($"MT5-获取服务器({model.server})-组({model.group})的客户{model.login}的订单失败：{code.ToString()}");
                        }
                    }
                    int clearCount = DBService.ClearOrder(orders, model.login);
                    if (clearCount > 0)
                    {
                        showMsg($"MT5-清除服务器({model.server})-组({model.group})的客户{model.login}的订单{orders.Count}条");
                    }
                }
                else
                {
                    showMsg($"MT5-获取服务器({model.server})-组({model.group})的客户{model.login}的订单数失败：{code.ToString()}");
                }
            }
            catch (Exception)
            {

                throw;
            }
        }

        #endregion

        #region  交易

        /// <summary>
        /// 获取所有用户
        /// </summary>
        public void GetDeal(GetUsersModel model)
        {
            try
            {
                uint total = 0;
                MTRetCode code;
                List<ulong> deals = new List<ulong>();
                long from = GettimeStamp(new DateTime(2023, 1, 1));
                long to = GettimeStamp(DateTime.Now);
                code = mT5WebAPI.DealGetTotal((ulong)model.login, from, to, out total);
                if (code == MTRetCode.MT_RET_OK)
                {
                    //计算页数
                    int pageNum = (int)Math.Ceiling(((decimal)total / (decimal)pageSize));
                    //变量所有页
                    for (int i = 0; i < pageNum; i++)
                    {
                        List<MTDeal> mTDeals = new List<MTDeal>();
                        uint offset = (uint)(i * pageSize);
                        code = mT5WebAPI.DealGetPage((ulong)model.login, from, to, offset, pageSize, out mTDeals);
                        if (code == MTRetCode.MT_RET_OK)
                        {
                            showMsg($"MT5-获取服务器({model.server})-组({model.group})的客户{model.login}的成交{mTDeals.Count}条");
                            if (mTDeals.Count > 0)
                            {
                                deals.AddRange(mTDeals.Select(k => k.Deal));
                                foreach (MTDeal mTDeal in mTDeals)
                                {
                                    int count = DBService.SaveDeal(mTDeal);
                                    showMsg($"MT5-获取服务器({model.server})-组({model.group})-交易账号({model.login})的成交信息({mTDeal.Deal}){(count > 0 ? "成功" : "失败")}");
                                }
                            }
                        }
                        else
                        {
                            showMsg($"MT5-获取服务器({model.server})-组({model.group})的客户{model.login}的成交失败：{code.ToString()}");
                        }
                    }
                    int clearCount = DBService.ClearDeal(deals, model.login);
                    if (clearCount > 0)
                    {
                        showMsg($"MT5-清除服务器({model.server})-组({model.group})的客户{model.login}的成交仓单{deals.Count}条");
                    }
                }
                else
                {
                    showMsg($"MT5-获取服务器({model.server})-组({model.group})的客户{model.login}的成交数失败：{code.ToString()}");
                }
            }
            catch (Exception)
            {

                throw;
            }
        }

        #endregion

        #region  持仓

        /// <summary>
        /// 获取所有用户
        /// </summary>
        public void GetPosition(GetUsersModel model)
        {
            try
            {
                uint total = 0;
                MTRetCode code;
                List<ulong> positions = new List<ulong>();
                code = mT5WebAPI.PositionGetTotal((ulong)model.login, out total);
                if (code == MTRetCode.MT_RET_OK)
                {
                    //计算页数
                    int pageNum = (int)Math.Ceiling(((decimal)total / (decimal)pageSize));
                    //变量所有页
                    for (int i = 0; i < pageNum; i++)
                    {
                        List<MTPosition> mTPositions = new List<MTPosition>();
                        uint offset = (uint)(i * pageSize);
                        code = mT5WebAPI.PositionGetPage((ulong)model.login, offset, pageSize, out mTPositions);
                        if (code == MTRetCode.MT_RET_OK)
                        {
                            showMsg($"MT5-获取服务器({model.server})-组({model.group})的客户{model.login}的开仓{mTPositions.Count}条");
                            if (mTPositions.Count > 0)
                            {
                                positions.AddRange(mTPositions.Select(k => k.ExpertPositionID));
                                foreach (MTPosition mTPosition in mTPositions)
                                {
                                    int count = DBService.SavePosition(mTPosition);
                                    showMsg($"MT5-获取服务器({model.server})-组({model.group})-交易账号({model.login})的开仓信息({mTPosition.ExpertPositionID}){(count > 0 ? "成功" : "失败")}");
                                }
                            }
                        }
                        else
                        {
                            showMsg($"MT5-获取服务器({model.server})-组({model.group})的客户{model.login}的开仓失败：{code.ToString()}");
                        }
                    }
                    //int clearCount = DBService.ClearPosition(positions, model.login);
                    //if (clearCount > 0)
                    //{
                    //    showMsg($"MT5-清除服务器({model.server})-组({model.group})的客户{model.login}的已平仓单{positions.Count}条");
                    //}
                }
                else
                {
                    showMsg($"MT5-获取服务器({model.server})-组({model.group})的客户{model.login}的开仓数失败：{code.ToString()}");
                }
            }
            catch (Exception)
            {

                throw;
            }
        }

        #endregion

        /// <summary>
        /// 获取当前时间戳
        /// </summary>
        /// <returns></returns>
        public static long GettimeStamp(DateTime datetime)
        {
            try
            {
                DateTime startTime = new DateTime(1970, 1, 1);
                long timeStamp = (long)(datetime - startTime).TotalSeconds;
                return timeStamp;
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}
